package com.xunji.user.controller;


import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xunji.user.common.Constant;
import com.xunji.user.common.R;
import com.xunji.user.common.Token;
import com.xunji.user.common.TokenUtils;
import com.xunji.user.config.MinioUtil;
import com.xunji.user.dto.MenuDto;
import com.xunji.user.entity.*;
import com.xunji.user.service.*;
import com.xunji.user.util.*;
import com.xunji.user.vo.rep.LoginResponse;
import com.xunji.user.vo.rep.UserPageResponse;
import com.xunji.user.vo.rep.UserQueryResponse;
import com.xunji.user.vo.req.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.validation.constraints.NotBlank;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Slf4j
@Api(tags = "用户管理")
@RestController
@RequestMapping("/user")
public class UserController {

    @Resource
    UserService userService;

    @Resource
    MenuService menuService;

    @Resource
    UserRoleService userRoleService;

    @Resource
    RoleMenuService roleMenuService;

    @Resource
    OrgService orgService;

    @Resource
    RoleService roleService;
    @Resource
    MinioUtil minioUtil;

    /**
     * web端过期时间
     */
    @Value("${web_expire_date}")
    private long webExpireDate;
    @Resource
    private CacheService cacheService;


    @PostMapping("/login")
    @ApiOperation(value = "用户登录", notes = "用户登录")
    public R login(@Validated @RequestBody LoginRequest request) {
        try {
            log.info("用户登录，用户名：{}，密码：{}", request.getLoginName(), request.getPassword());
            User user = userService.loginByName(request.getLoginName());
            if (user == null) return R.failure("用户名或密码错误，请重新输入");
            boolean matches = SpringUtil.getBean(PasswordEncoder.class).matches(Base64Util.decode(request.getPassword()), user.getPassword());
            if (!matches) {
                return R.failure("用户名或密码错误，请重新输入");
            }
            LoginResponse response = new LoginResponse();
            response.setId(user.getId());
            response.setGender(user.getGender());
            response.setLoginName(user.getLoginName());
            //根据用户查询角色
            List<UserRole> roles = userRoleService.selectByUserId(user.getId());
            //根据角色查询菜单
            if (!CollectionUtils.isEmpty(roles)) {
                List<String> roleIds = roles.stream().map(UserRole::getRoleId).collect(Collectors.toList());
                List<Role> roleList = roleService.listByIds(roleIds);
                response.setRoles(roleList);
                List<RoleMenu> menus = roleMenuService.getByRoleIds(roleIds);
                if (!CollectionUtils.isEmpty(menus)) {
                    Set<Integer> menuIds = menus.stream().map(RoleMenu::getMenuId).collect(Collectors.toSet());
                    List<Menu> menuList = menuService.getMenusByIds(new ArrayList<>(menuIds));
                    List<MenuDto> menuDtos = menuList.stream().map(MenuDto::getInstance).collect(Collectors.toList());
                    response.setMenus(makePidTree(menuDtos, 0));
                }
            }
            String tokenName = UUIDUtil.getUUID().toUpperCase() + TokenUtils.CACHE_DELIMITER + user.getId();
            String token = Token.getInstance().getToken(tokenName, webExpireDate * Constant.ONE_DAY);
            String cacheKey = TokenUtils.genSessionKey(user.getId(), "0");
            cacheService.set(cacheKey, tokenName, System.currentTimeMillis());
            response.setName(user.getName());
            response.setToken(token);
            return R.success(response);
        } catch (Exception e) {
            e.printStackTrace();
            return R.failure("用户名或密码错误，请重新输入");
        }
    }

    private List<MenuDto> makePidTree(List<MenuDto> orgQueryResponses, Integer pid) {
        List<MenuDto> children = orgQueryResponses.stream().filter(x -> x.getPId().equals(pid)).sorted(Comparator.comparing(MenuDto::getWeight)).collect(Collectors.toList());
        List<MenuDto> successor = orgQueryResponses.stream().filter(x -> !x.getPId().equals(pid)).collect(Collectors.toList());
        children.forEach(x -> {
            x.setChildren(makePidTree(successor, x.getId()));
        });
        return children;
    }


    @PostMapping("/page")
    @ApiOperation(value = "查询人员", notes = "查询人员")
    public R getRoles(@Validated @RequestBody UserQueryRequest request) {
        try {
            Page<UserPageResponse> userPage = userService.page(request);
            return R.success(userPage);
        } catch (Exception e) {
            log.error("查询人员失败，e->{}", e);
            return R.failure("查询失败");
        }
    }

    @PostMapping("/list")
    @ApiOperation(value = "人员搜索", notes = "人员搜索")
    public R getUserList(@RequestBody UserSearchRequest searchRequest, HttpServletRequest request) {
        try {
            String userId = RequestContextUtil.getUser(request);
            List<User> users = userService.userSearchList(searchRequest, userId);
            return R.success(users);
        } catch (Exception e) {
            log.error("查询人员失败，e->{}", e);
            return R.failure("查询失败");
        }
    }

    @GetMapping("/{id}")
    @ApiOperation(value = "查看用户详情", notes = "查看用户详情")
    public R getUser(@PathVariable("id") String id) {
        User user = userService.getUserById(id);
        UserQueryResponse response = UserQueryResponse.getInstance(user);
        Org org = orgService.getOrgById(user.getDepartmentId());
        response.setDepartmentName(org.getName());
        List<UserRole> userRoles = userRoleService.selectByUserId(user.getId());
        if (!CollectionUtils.isEmpty(userRoles)) {
            response.setRoles(roleService.listByIds(userRoles.stream().map(UserRole::getRoleId).collect(Collectors.toList())));
        }
        String imagePreviewUrl = "";
        try {
            imagePreviewUrl = minioUtil.getPreviewUrl(user.getImage());
        } catch (Exception e) {
            log.error("获取头像预览url失败->{},", e);
        }
        response.setImagePreviewUrl(imagePreviewUrl);
        return R.success(response);
    }

    @GetMapping("/feign/user/name/{userId}")
    @ApiOperation(value = "查询用户名称", notes = "查看用户详情")
    public R getUserName(@PathVariable String userId) {
        User user = userService.getUserById(userId);
        return R.success(user.getName());
    }


    @PutMapping("")
    @ApiOperation(value = "添加用户", notes = "添加用户")
    public R addUser(@RequestBody UserAddRequest request) {
        try {
            userService.addUser(request);
            return R.success();
        } catch (Exception e) {
            log.error("添加用户失败，e->{}", e);
            return R.failure("添加用户失败");
        }
    }

    @PostMapping("")
    @ApiOperation(value = "修改用户", notes = "修改用户")
    public R updateUser(@RequestBody UserUpdateRequest userUpdateRequest) {
        try {
            userService.updateUser(userUpdateRequest);
            return R.success();
        } catch (Exception e) {
            log.error("修改用户失败，e->{}", e);
            return R.failure("修改用户失败");
        }
    }

    @DeleteMapping("/{id}")
    @ApiOperation(value = "删除用户", notes = "删除用户")
    public R deleteUser(@PathVariable("id") String id) {
        try {
            userService.deleteUser(id);
            return R.success();
        } catch (Exception e) {
            log.error("删除用户失败，e->{}", e);
            return R.failure("删除用户失败");
        }
    }

    @DeleteMapping("")
    @ApiOperation(value = "批量删除用户", notes = "批量删除用户")
    public R deleteUsers(@RequestParam List<String> ids) {
        try {
            ids.stream().forEach(id -> {
                userService.deleteUser(id);
            });
            return R.success();
        } catch (Exception e) {
            log.error("批量删除用户失败，e->{}", e);
            return R.failure("批量删除用户失败");
        }
    }


    @PostMapping("/pwd/{id}")
    @ApiOperation(value = "重置密码", notes = "重置密码")
    public R resetPwd(@PathVariable("id") String id) {
        try {
            userService.restPwd(id);
            return R.success();
        } catch (Exception e) {
            log.error("重置密码失败，e->{}", e);
            return R.failure("重置密码失败");
        }
    }

    @PostMapping("/pwd/new")
    public R updatePwd(@RequestBody UpdatePwdRequest request, HttpServletRequest servletRequest) {
        String userId = RequestContextUtil.getUser(servletRequest);
        User user = userService.getUserById(userId);
        boolean matches = SpringUtil.getBean(PasswordEncoder.class).matches(request.getOldPwd(), user.getPassword());
        if (!matches) {
            return R.failure("输入的原始密码错误，请重新输入");
        }
        String newPwd = request.getNewPwd();
        if (StringUtils.isEmpty(newPwd)) {
            return R.failure("新密码不能为空，请重新输入");
        }
        if (newPwd.length() < 6) {
            return R.failure("密码不得小于6位");
        }
        /*if (newPwd.contains(user.getLoginName())) {
            return R.failure("新密码不能包含登录名，请重新输入");
        }*/
        if (!PwdUtil.effectiveNew(request.getNewPwd())) {
            return R.failure("新密码至少包含大写字母、小写字母、数字中的2种");
        }
        userService.updatePwd(user.getId(), request.getNewPwd());
        return R.success("密码修改成功");
    }

    @PostMapping("/login_name")
    @ApiOperation(value = "获取登录名", notes = "获取登录名")
    public R getLoginNameByName(@NotBlank @RequestParam("name") String name) {
        String pinyin = PinyinHelper.getPinYin(name);
        List<User> users = userService.getSimilarAccountByLoginName(pinyin);
        String regex = "^" + pinyin + "\\d*$";
        Pattern pattern = Pattern.compile(regex);
        int sn = 0;
        for (User user : users) {
            String loginName = user.getLoginName();
            if (StringUtils.isNotEmpty(loginName)) {
                Matcher matcher = pattern.matcher(loginName);
                if (matcher.matches()) {
                    sn++;
                }
            }
        }
        pinyin = sn > 0 ? pinyin + sn : pinyin;
        return R.success(pinyin);
    }

/*    @PostMapping("/image")
    @ApiOperation(value = "上传头像", notes = "上传头像")
    public R uploadImage(@RequestParam("file") MultipartFile file) {
        try {
            if (file.getSize() > 204800) {
                return R.failure("请上传小于200kb的头像图片");
            }
            String fileName = minioUtil.uploadFile(Constant.LP_BUCKET, Constant.HEAD_IMAGE_PATH, file);
            String previewUrl = minioUtil.getPreviewUrl(Constant.LP_BUCKET, fileName);
            return R.success(HeadImageUploadResponse.getInstance(new MinioUploadDto(fileName, previewUrl)));
        } catch (Exception e) {
            return R.failure("头像上传失败");
        }
    }*/

}
